<script>
import FormButton from "../Form/button.vue";
import FormText from "../Form/text.vue";
import FormSelect from "../Form/select.vue";
import FormSelectDay from "../Form/selectday.vue";
// import FormSelectDatepicker from "../Form/selectDatepicker.vue";
import FormDatePicker from "../Form/datepicker.vue";
import FormSelectRow from "../Form/selectRow.vue";
import FormRadio from "../Form/radio.vue";
import FormCheckbox from "../Form/checkbox.vue";
import FormEditor from "../Form/editor.vue";
import FormTextarea from "../Form/textarea.vue";
import FormTag from "../Form/tag.vue";
import FormUpload from "../Form/upload.vue";
import { merge, isFunction, isNil } from "lodash";
export default {
  props: {
    formOptions: {
      type: Object,
    },
  },
  inject: ["context"],
  data() {
    return {
      formData: {},
      resetFormData: {},
      loading: {
        submit: false,
        cancel: false,
      },
      formItems: [],
    };
  },
  computed: {
    formOptionsSync() {
      const formOptions = merge(
        {
          isDialog: false,
          columns: [],
          submit: false,
          cancel: false,
          reject: false,
          labelWidth: "0",
          rules: {},
        },
        this.formOptions
      );
      formOptions.columns.forEach((it) => {
        const context = it.context || this;
        it.labelWidth =
          isNil(it.labelWidth) && it.label
            ? `${formOptions.labelWidth}`
            : `${it.labelWidth || "0px"}`;
        const rules = it.rules || [];
        if (it.require) {
          rules.push({
            required: true,
            message: $AONE_LAN.plsInput + it.label,
            trigger: "blur",
          });
        }
        formOptions.rules[it.prop] = rules;
        for (const itKey in it) {
          if (typeof it[itKey] == "function") {
            it[itKey] = it[itKey].bind(context);
          }
        }
      });
      return formOptions;
    },
    formColumns() {
      return this.formOptionsSync.columns.filter(
        (it) => it && it.visiable !== false
      );
    },
    className() {
      return this.formOptionsSync.class || "";
    },
  },
  watch: {
    formOptions: {
      immediate: true,
      deep: true,
      handler(data) {
        data.columns.filter(Boolean).forEach((it) => {
          if (it.prop && !Reflect.has(this.formData, it.prop)) {
            // select 多选时，和checkbox两种组件是数组
            if (
              (it.comtype == "select" &&
                it.multiple &&
                it.value === undefined) ||
              (it.comtype == "checkbox" && it.value === undefined)
            ) {
              it.value = [];
            }
            // selectday 日期默认0
            if (it.comtype == "selectday") {
              if (it.value === undefined) {
                it.value = 0;
              }
              if (it.startTimeField) {
                this.$set(this.formData, it.startTimeField, "");
                this.$set(this.resetFormData, it.startTimeField, "");
              }
              if (it.endTimeField) {
                this.$set(this.formData, it.endTimeField, "");
                this.$set(this.resetFormData, it.endTimeField, "");
              }
            }
            // const value = it.value === undefined ? "" : it.value;
            const value = it.value;
            this.$set(this.formData, it.prop, value);
            this.$set(this.resetFormData, it.prop, value);
            if (Reflect.has(it, "value") && !Reflect.has(it, "prop")) {
              console.warn("组件传了value但是没传prop");
            }
          }
        });
      },
    },
    formData: {
      immediate: true,
      deep: true,
      handler(val) {
        this.onFormDataUpdate(val);
      },
    },
  },
  methods: {
    renderFormItem() {
      const formItems = [];
      this.formColumns.filter(Boolean).map((it, idx) => {
        const comtype = it.comtype.toLowerCase().replace(/_/g, "");
        if (it.visiable !== false) {
          const className = `aone-form-item-column aone-form-item-${it.prop}`;
          const refName = it.prop ? it.prop : `idx${idx}`;
          switch (comtype) {
            case "text": {
              formItems.push(
                <el-form-item
                  label={it.label}
                  label-width={it.labelWidth}
                  class={it.class}
                  rules={it.rules}
                  prop={it.prop}
                  ref={refName}
                  style={{ width: it.width }}
                  scopedSlots={{
                    label: () => it.label,
                  }}
                >
                  {it.renderHeader?.()}
                  <FormText
                    key={`key-${it.prop}-${idx}`}
                    class={"aone-form-item-comtype " + className}
                    style={it.style}
                    {...{ props: it }}
                    formData={this.formData}
                  />
                  {it.renderFooter?.()}
                </el-form-item>
              );
              break;
            }
            case "radio": {
              formItems.push(
                <el-form-item
                  label={it.label}
                  class={it.class}
                  label-width={it.labelWidth}
                  rules={it.rules}
                  prop={it.prop}
                  ref={refName}
                  scopedSlots={{
                    label: () => it.label,
                  }}
                >
                  {it.renderHeader?.()}
                  <FormRadio
                    key={`key-${it.prop}-${idx}`}
                    class={"aone-form-item-comtype " + className}
                    style={it.style}
                    {...{ props: it }}
                    formData={this.formData}
                  />
                  {it.renderFooter?.()}
                </el-form-item>
              );
              break;
            }
            case "checkbox": {
              formItems.push(
                <el-form-item
                  label={it.label}
                  class={it.class}
                  label-width={it.labelWidth}
                  rules={it.rules}
                  prop={it.prop}
                  ref={refName}
                  scopedSlots={{
                    label: () => it.label,
                  }}
                >
                  {it.renderHeader?.()}
                  <FormCheckbox
                    key={`key-${it.prop}-${idx}`}
                    class={"aone-form-item-comtype " + className}
                    style={it.style}
                    {...{ props: it }}
                    formData={this.formData}
                  />
                  {it.renderFooter?.()}
                </el-form-item>
              );
              break;
            }
            case "tag": {
              formItems.push(
                <el-form-item
                  label={it.label}
                  class={it.class}
                  label-width={it.labelWidth}
                  rules={it.rules}
                  prop={it.prop}
                  ref={refName}
                  scopedSlots={{
                    label: () => it.label,
                  }}
                >
                  {it.renderHeader?.()}
                  <FormTag
                    key={`key-${it.prop}-${idx}`}
                    class={"aone-form-item-comtype " + className}
                    style={it.style}
                    {...{ props: it }}
                  />
                  {it.renderFooter?.()}
                </el-form-item>
              );
              break;
            }
            case "select": {
              formItems.push(
                <el-form-item
                  label={it.label}
                  class={it.class}
                  label-width={it.labelWidth}
                  rules={it.rules}
                  prop={it.prop}
                  ref={refName}
                  style={{ width: it.width }}
                  scopedSlots={{
                    label: () => it.label,
                  }}
                >
                  {it.renderHeader?.()}
                  <FormSelect
                    key={`key-${it.prop}-${idx}`}
                    class={"aone-form-item-comtype " + className}
                    style={it.style}
                    {...{ props: it }}
                    formData={this.formData}
                  />
                  {it.renderFooter?.()}
                </el-form-item>
              );
              break;
            }
            case "datepicker": {
              formItems.push(
                <el-form-item
                  label={it.label}
                  class={it.class}
                  label-width={it.labelWidth}
                  rules={it.rules}
                  prop={it.prop}
                  ref={refName}
                  style={{ width: it.width }}
                  scopedSlots={{
                    label: () => it.label,
                  }}
                >
                  {it.renderHeader?.()}
                  <FormDatePicker
                    key={`key-${it.prop}-${idx}`}
                    class={"aone-form-item-comtype " + className}
                    style={it.style}
                    {...{ props: it }}
                    formData={this.formData}
                  />
                  {it.renderFooter?.()}
                </el-form-item>
              );
              break;
            }
            case "selectday": {
              formItems.push(
                <el-form-item
                  label={it.label}
                  class={it.class}
                  label-width={it.labelWidth}
                  rules={it.rules}
                  prop={it.prop}
                  ref={refName}
                  style={{ width: it.width }}
                  scopedSlots={{
                    label: () => it.label,
                  }}
                >
                  {it.renderHeader?.()}
                  <FormSelectDay
                    key={`key-${it.prop}-${idx}`}
                    class={"aone-form-item-comtype " + className}
                    style={it.style}
                    {...{ props: it }}
                    onFormDataUpdate={this.onFormDataUpdate}
                    formData={this.formData}
                  />
                  {it.renderFooter?.()}
                </el-form-item>
              );
              break;
            }
            case "selectrow": {
              formItems.push(
                <el-form-item
                  label={it.label}
                  class={it.class}
                  label-width={it.labelWidth}
                  rules={it.rules}
                  prop={it.prop}
                  ref={refName}
                  style={{ width: it.width }}
                  scopedSlots={{
                    label: () => it.label,
                  }}
                >
                  {it.renderHeader?.()}
                  <FormSelectRow
                    key={`key-${it.prop}-${idx}`}
                    class={"aone-form-item-comtype " + className}
                    style={it.style}
                    {...{ props: it }}
                    formData={this.formData}
                  />
                  {it.renderFooter?.()}
                </el-form-item>
              );
              break;
            }
            case "upload": {
              formItems.push(
                <el-form-item
                  label={it.label}
                  class={it.class}
                  label-width={it.labelWidth}
                  rules={it.rules}
                  prop={it.prop}
                  ref={refName}
                  style={{ width: it.width }}
                  scopedSlots={{
                    label: () => it.label,
                  }}
                >
                  {it.renderHeader?.()}
                  <FormUpload
                    key={`key-${it.prop}-${idx}`}
                    class={"aone-form-item-comtype " + className}
                    style={it.style}
                    {...{ props: it }}
                    formData={this.formData}
                  />
                  {it.renderFooter?.()}
                </el-form-item>
              );
              break;
            }
            case "editor": {
              formItems.push(
                <el-form-item
                  label={it.label}
                  class={it.class}
                  label-width={it.labelWidth}
                  rules={it.rules}
                  prop={it.prop}
                  ref={refName}
                  scopedSlots={{
                    label: () => it.label,
                  }}
                >
                  {it.renderHeader?.()}
                  <FormEditor
                    key={`key-${it.prop}-${idx}`}
                    class={"aone-form-item-comtype " + className}
                    style={it.style}
                    {...{ props: it }}
                    formData={this.formData}
                  />
                  {it.renderFooter?.()}
                </el-form-item>
              );
              break;
            }
            case "textarea": {
              formItems.push(
                <el-form-item
                  label={it.label}
                  class={it.class}
                  label-width={it.labelWidth}
                  rules={it.rules}
                  prop={it.prop}
                  ref={refName}
                  scopedSlots={{
                    label: () => it.label,
                  }}
                >
                  {it.renderHeader?.()}
                  <FormTextarea
                    key={`key-${it.prop}-${idx}`}
                    class={"aone-form-item-comtype " + className}
                    style={it.style}
                    {...{ props: it }}
                    formData={this.formData}
                  />
                  {it.renderFooter?.()}
                </el-form-item>
              );
              break;
            }
            case "button": {
              formItems.push(
                <el-form-item label-width={it.labelWidth} class={it.class}>
                  {it.renderHeader?.()}
                  <FormButton
                    key={`key-${it.prop}-${idx}`}
                    class={className}
                    style={it.style}
                    {...{ props: it }}
                    formData={this.formData}
                  />
                  {it.renderFooter?.()}
                </el-form-item>
              );
              break;
            }
            case "vnode": {
              if (isFunction(it.render)) {
                // 可以通过外部特别制定上下文对象
                const context = it.context || this;
                const renderLabel = () => {
                  return it.label ? (
                    <p class="label">
                      {it.require ? <span class="red">*</span> : null}
                      {it.label}：
                    </p>
                  ) : null;
                };
                formItems.push(
                  <el-form-item
                    label={it.label}
                    class={it.class}
                    label-width={it.labelWidth}
                    rules={it.rules}
                    prop={it.prop}
                    ref={refName}
                    scopedSlots={{
                      label: () => it.label,
                    }}
                  >
                    {it.renderHeader?.()}
                    <div
                      key={`key-${it.prop}-${idx}`}
                      style={it.style}
                      class={"aone-form-item aone-form-item-vnode " + className}
                    >
                      <div class="vnode">
                        {/* renderLabel() */}
                        {it.render.bind(context)()}
                      </div>
                    </div>
                    {it.renderFooter?.()}
                  </el-form-item>
                );
              }
              break;
            }
          }
        }
        // 换行
        if (it.br) {
          formItems.push(<div class={`aone-form-item-br-devide`}></div>);
        }
      });
      this.formItems = formItems;
      return formItems;
    },
    onSubmit() {
      // 验证
      this.$refs.form.validate((valid) => {
        if (valid) {
          this.context?.onSubmit?.(this.formData);
        } else {
          console.log("error submit!!");
          return false;
        }
      });
    },
    onReject() {
      // 验证
      this.$refs.form.validate((valid) => {
        if (valid) {
          this.context?.onReject?.(this.formData);
        } else {
          console.log("error reject!!");
          return false;
        }
      });
    },
    async checkValidateForm() {
      await new Promise((resolve) => {
        this.$refs.form.validate((valid) => {
          resolve(valid);
        });
      });
    },
    onCancel() {
      this.context?.onCancel?.(this.formData);
    },
    onReset() {
      this.formItems.forEach((item) => {
        let children = item.child?.$children;
        if (children) {
          if (!Array.isArray(children)) {
            children = [children];
          }
          children.forEach((child) => {
            child.onReset?.(this.resetFormData);
          });
        }
      });
    },
    onFormDataUpdate(val) {
      this.$emit("formDataUpdate", val);
    },
  },
  render() {
    return (
      <el-form
        ref="form"
        size="mini"
        rules={this.formOptionsSync.rules}
        label-width={this.formOptionsSync.labelWidth}
        class={"aone-form " + this.className}
        {...{
          props: {
            model: this.formData,
          },
        }}
      >
        {this.renderFormItem()}
      </el-form>
    );
  },
};
</script>

<style lang="scss" scoped>
.aone-form-item-br-devide {
  width: 100%;
  height: 10px;
}
</style>
